home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 351-375 / disk_352 / treewalk / willfit.c < prev   
C/C++ Source or Header  |  1992-05-06  |  6KB  |  201 lines

  1. /*
  2.  * willfit - Decide if one or more directories will fit on the given
  3.  * device.
  4.  *
  5.  * Copyright (c) 1990, Mike Meyer
  6.  *
  7.  * Usage: willfit device [directories]
  8.  *
  9.  * Decides whether or not there's enough room on device for the given
  10.  * directories (and all files contained inside them). Willfit starts by
  11.  * getting the number of free blocks on the device, and then keeps a
  12.  * running total of free blocks left on the device as it scans each tree.
  13.  * If there are enough free blocks, it prints 'yes' followed by the name
  14.  * of the directory as the user typed it. If there aren't enough blocks,
  15.  * it prints the shortfall for that directory. After the first shortfall,
  16.  * it prints how large each directory (and etc.) is.
  17.  *
  18.  * Device may be any file that's on the device of interest. As a special
  19.  * case, if the device is "-" then willfit uses the current device, and
  20.  * acts as if it already ran out of space, so you get a list of how many
  21.  * disk blocks each argument directory consumes. There is no RETURN_WARN
  22.  * in this case.
  23.  *
  24.  * The return value is RETURN_OK if all arguments fit, RETURN_WARN if
  25.  * some arguments wouldn't fit, and RETURN_ERROR if some arguments didn't
  26.  * exist. RETURN_FAIL indicates out of memory, or unable to get data for
  27.  * device.
  28.  *
  29.  * Note that the output of "willfit -" may not agree with the output of
  30.  * list. Willfit always reports the number of blocks taken up for the
  31.  * file, including all file system data blocks. List reports the block
  32.  * count from the file information block, which just includes the data
  33.  * blocks for the old file system, and includes all file system blocks
  34.  * except maybe the header block for the fast file system. This means
  35.  * that willfit may report one block higher than list, and possibly more.
  36.  * That willfit reports the header block sometimes means there is one extra
  37.  * block on the device, if you ask it about a directory which already exists
  38.  * on the destination device. For example, if "willfit df0: tree" reports
  39.  * a shortfall of one block, but the directory tree already exists on df0:,
  40.  * then "copy tree df0:tree all" should work.
  41.  */
  42.  
  43. #include <exec/types.h>
  44. #include <libraries/dos.h>
  45. #include <proto/dos.h>
  46. #include <proto/exec.h>
  47. #include <dos.h>
  48.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include "treewalk.h"
  53.  
  54.     
  55. /* Globals, because the nature of the beast requires them */
  56. static char            *my_name ;    /* Name I was invoked by */
  57. static long            running_total ;    /* Tree size so far */
  58. static long            blocks_free ;    /* Blocks free on device */
  59. static struct FileInfoBlock    *fib ;        /* Scratch fib me to play in */
  60. static int            blocksize = 0 ;    /* data bytes in a block */
  61.  
  62. /*
  63.  * getdevdata - gets the device data we need to keep around.
  64.  */
  65. static int
  66. getdevdata(char *dev) {
  67.     BPTR            lock ;
  68.     struct InfoData        *fid ;
  69.  
  70.     /* Get a lock */
  71.     if ((lock = Lock(dev, ACCESS_READ)) == NULL) {
  72.         fprintf(stderr, "%s: Can't lock device %s\n", my_name, dev) ;
  73.         return FALSE ;
  74.         }
  75.  
  76.     /* Get space for an InfoData structure */
  77.     if ((fid = (struct InfoData *)
  78.         AllocMem(sizeof(struct InfoData), 0)) == NULL) {
  79.             fprintf(stderr, "%s: out of memory\n", my_name) ;
  80.             return FALSE ;
  81.             }
  82.  
  83.     /* Get the info we need */
  84.     if (!Info(lock, fid)) {
  85.         FreeMem(fid, sizeof(struct InfoData)) ;
  86.         fprintf(stderr, "%s: Can't get info on %s\n", my_name, dev) ;
  87.         return FALSE ;
  88.         }
  89.  
  90.     /* set the globals needed from this device */
  91.     blocksize = fid->id_BytesPerBlock ;
  92.     blocks_free = fid->id_NumBlocks - fid->id_NumBlocksUsed ;
  93.  
  94.     /* Clean up and exit */
  95.     FreeMem(fid, sizeof(struct InfoData)) ;
  96.     return TRUE ;
  97.     }
  98.  
  99. /*
  100.  * This is a kludge, correct for 512 byte block file systems. There are
  101.  * no other kinds as yet, and I expect this to appear somewhere where it
  102.  * can be found should new block sizes appear.
  103.  */
  104. #define    EXTENTS_PER_BLOCK    72
  105.  
  106. /*
  107.  * sumup - tracks the running sum of how big things are.
  108.  */
  109. #define NUMBER_USED(m, n) ((n / m) + (n % m ? 1 : 0))
  110. static int
  111. sumup(BPTR lock, struct FileInfoBlock *fib) {
  112.     long    blocks ;
  113.  
  114.     /* Do we gotta stop now? */
  115.     if (SetSignal(0, 0) & SIGBREAKF_CTRL_C) return TREE_STOP ;
  116.  
  117.     /* Ignore directory headers */
  118.     if (fib == NULL) return TREE_CONT ;
  119.  
  120.     /* If we got a real fib, add in data blocks plus file system blocks */
  121.     blocks = NUMBER_USED(blocksize, fib->fib_Size) ;
  122.     running_total += blocks + NUMBER_USED(EXTENTS_PER_BLOCK, blocks) ;
  123.  
  124.     /* zero-length files use a header that doesn't show above */
  125.     if (fib->fib_Size == 0) running_total += 1 ;
  126.  
  127.     /* And continue the walk */
  128.     return TREE_CONT ;
  129.     }
  130.  
  131. /*
  132.  * du - arrange to let treewalk do the actual work, with the sumup routine
  133.  * to keep a running total for this tree.
  134.  */
  135. static int
  136. du(char *dir) {
  137.     BPTR    lock ;
  138.     int    stat ;
  139.  
  140.     /* Make sure we've got something we can really work on */
  141.     if ((lock = Lock(dir, ACCESS_READ)) == NULL) {
  142.         fprintf(stderr, "%s: Can't lock directory %s\n", my_name, dir) ;
  143.         return TRUE ;
  144.         }
  145.  
  146.     if (!Examine(lock, fib)) {
  147.         fprintf(stderr, "%s: Can't examine %s\n", my_name, dir) ;
  148.         return TRUE ;
  149.         }
  150.  
  151.     /* Count the block in the top node */
  152.     running_total = 0 ;
  153.     sumup(lock, fib) ;
  154.  
  155.     /* Walk the tree and count all the blocks in it */
  156.     stat = treewalk(lock, sumup, TREE_PRE) ;
  157.  
  158.     /* Tell the user, and clean up */
  159.     UnLock(lock) ;
  160.     if (blocks_free <= 0)
  161.         printf("%ld\t%s\n", running_total, *dir ? dir : "\"\"") ;
  162.     else if ((blocks_free -= running_total) >= 0) printf("yes\t%s\n", dir) ;
  163.     else printf("%ld\t%s\n", -blocks_free, *dir ? dir : "") ;
  164.  
  165.     return !stat ;
  166.     }
  167.  
  168. /*
  169.  * main - just call du on each argument.
  170.  */
  171. void
  172. main(int argc, char **argv) {
  173.     int    error = FALSE ;
  174.  
  175.     my_name = argv[0] ;
  176.  
  177.     /* get the device data, if possible */
  178.     if (strcmp(*++argv, "-")) {
  179.         if (!getdevdata(*argv)) exit(RETURN_FAIL) ;
  180.         }
  181.     else  {
  182.         if (!getdevdata(":")) exit(RETURN_FAIL) ;
  183.         blocks_free = 0 ;
  184.         }
  185.  
  186.     /* Get a scratch fib for du to use */
  187.     if ((fib = (struct FileInfoBlock *)
  188.         AllocMem(sizeof(struct FileInfoBlock), 0)) == NULL) {
  189.             fprintf(stderr, "%s: out of memory\n", my_name) ;
  190.             exit(RETURN_FAIL) ;
  191.             }
  192.  
  193.     if (!*++argv) error = du("") ;
  194.     else
  195.         do error |= du(*argv) ;
  196.         while (*++argv) ;
  197.  
  198.     FreeMem(fib, sizeof(struct FileInfoBlock)) ;
  199.     exit(error ? RETURN_ERROR : (blocks_free < 0 ? RETURN_WARN : RETURN_OK)) ;
  200.     }
  201.